﻿using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Text;

namespace Tequila.Phone.Sharing
{
    /// <summary>
    /// Isolated storage <see cref="IFileStorageManager">file storage manager</see>.
    /// </summary>
    public class IsolatedStorageFileStorageManager : IFileStorageManager
    {
        private const string ImageFilePathTemplate = "{0}.jpg";
        private const string PagePathTemplate = "{0}.html";

        private readonly IsolatedStorageFile _isoStore = IsolatedStorageFile.GetUserStoreForApplication();

        /// <summary>
        /// Generates unique image path.
        /// </summary>
        /// <returns></returns>
        public string GenerateUniqueImagePath()
        {
            return string.Format(ImageFilePathTemplate, Guid.NewGuid());
        }

        /// <summary>
        /// Generates unique html path.
        /// </summary>
        /// <returns></returns>
        public string GenerateUniqueHtmlPath()
        {
            return string.Format(PagePathTemplate, Guid.NewGuid());
        }

        /// <summary>
        /// Saves content into isolated storage.
        /// </summary>
        /// <param name="content"></param>
        /// <param name="localPath"></param>
        public void SaveFile(string content, string localPath)
        {
            CreateDirectoryIfRequired(localPath);
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(content)))
            {
                SaveFile(ms, localPath);
            }
        }

        /// <summary>
        /// Copies source content from isolated storage to destination content in isolated storage.
        /// </summary>
        /// <exception cref="IsolatedStorageException"></exception>
        /// <param name="sourcePath"></param>
        /// <param name="destPath"></param>
        public void CopyFile(string sourcePath, string destPath)
        {
            try
            {
                CreateDirectoryIfRequired(destPath);
                if (_isoStore.FileExists(sourcePath))
                {
                    if (_isoStore.FileExists(destPath))
                        _isoStore.DeleteFile(destPath);
                    _isoStore.CopyFile(sourcePath, destPath);
                }

            }
            catch (IsolatedStorageException isex)
            {
                throw new FileStorageManagerException(
                    string.Format("Can't copy from {0} to {1}", sourcePath, destPath), isex);
            }
        }

        /// <summary>
        /// Saves stream source in isolated storage.
        /// </summary>
        /// <exception cref="IsolatedStorageException"></exception>
        /// <param name="source"></param>
        /// <param name="localPath"></param>
        public void SaveFile(Stream source, string localPath)
        {
            try
            {
                CreateDirectoryIfRequired(localPath);
                if (_isoStore.FileExists(localPath))
                    _isoStore.DeleteFile(localPath);

                using (var sw = new BinaryWriter(_isoStore.CreateFile(localPath)))
                {
                    //try
                    //{
                    source.Seek(0, SeekOrigin.Begin);
                    var sr = new BinaryReader(source);
                    var content = sr.ReadBytes((int) source.Length);
                    sw.Write(content);
                    source.Seek(0, SeekOrigin.Begin);
                    //}
                    //catch(IOException ioex)
                    //{
                    //}
                }

            }
            catch (IsolatedStorageException isex)
            {
                throw new FileStorageManagerException(string.Format("Can't save {0}", localPath), isex);
            }
        }

        /// <summary>
        /// Creates <see cref="Stream">stream</see> containing content from isolated storage.
        /// </summary>
        /// <param name="localPath"></param>
        /// <exception cref="IsolatedStorageException"></exception>
        /// <returns></returns>
        public Stream CreateFile(string localPath)
        {
            try
            {
                CreateDirectoryIfRequired(localPath);
                if (_isoStore.FileExists(localPath))
                    _isoStore.DeleteFile(localPath);
                return _isoStore.CreateFile(localPath);

            }
            catch (IsolatedStorageException isex)
            {
                throw new FileStorageManagerException(string.Format("Can't save {0}", localPath), isex);
            }
        }

        /// <summary>
        /// Determines whether object exists or not in isolated storage.
        /// </summary>
        /// <param name="localPath"></param>
        /// <returns></returns>
        public bool IsExists(string localPath)
        {
            return _isoStore.FileExists(localPath);
        }

        /// <summary>
        /// Removes the file from isolated storage.
        /// </summary>
        /// <param name="localPath"></param>
        /// <exception cref="IsolatedStorageException"></exception>
        public void DeleteFile(string localPath)
        {
            try
            {
                if (IsExists(localPath))
                    _isoStore.DeleteFile(localPath);
            }
            catch (IsolatedStorageException isex)
            {
                throw new FileStorageManagerException(string.Format("Can't save {0}", localPath), isex);
            }
        }

        /// <summary>
        /// Reads content from isolated storage by provided path.
        /// </summary>
        /// <param name="localPath"></param>
        /// <returns></returns>
        public string ReadFile(string localPath)
        {
            try
            {
                using (var storageStream = new IsolatedStorageFileStream(localPath, FileMode.Open, _isoStore))
                {
                    var sr = new StreamReader(storageStream);
                    return sr.ReadToEnd();
                }
            }
            catch (IsolatedStorageException isex)
            {
                throw new FileStorageManagerException(string.Format("Can't read content {0}", localPath), isex);
            }
        }

        /// <summary>
        /// Opens content by provided path in isolated storage as <see cref="Stream">stream</see>.
        /// </summary>
        /// <param name="localPath"></param>
        /// <returns></returns>
        public Stream OpenFile(string localPath)
        {
            try
            {
                return new IsolatedStorageFileStream(
                    localPath, FileMode.Open, _isoStore);
            }
            catch (IsolatedStorageException isex)
            {
                throw new FileStorageManagerException(string.Format("Can't open {0}", localPath), isex);
            }
        }

        /// <summary>
        /// Determines the last update time of content by provided path.
        /// </summary>
        /// <param name="localPath"></param>
        /// <returns></returns>
        public DateTimeOffset GetLastUpdateTime(string localPath)
        {
            return _isoStore.GetLastWriteTime(localPath);
        }

        private void CreateDirectoryIfRequired(string filePath)
        {
            var parts = filePath.Split("/".ToCharArray());
            if (parts.Length == 0)
                return;
            var directoryPath = string.Empty;
            for (var i = 0; i < parts.Length - 1; i++)
            {
                directoryPath += "/" + parts[i];
                directoryPath = directoryPath.Replace("//", "/");
                if (_isoStore.DirectoryExists(directoryPath))
                    continue;
                _isoStore.CreateDirectory(directoryPath);
            }
        }
    }
}
